package ti;

import java.awt.event.*;
import java.io.File;
import java.io.FileNotFoundException;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;

public class ParserWindow extends JFrame {

    /*-----------------------*
     * Variable Declarations *
     *-----------------------*/
    private static final long serialVersionUID = 0x0557A9A3L;
    private JFileChooser browseFileChooser = new JFileChooser();
    private ButtonGroup parseModeRadioButtonGroup = new ButtonGroup();
    private JRadioButton parseTXTRadioButton = new JRadioButton();
    private JRadioButton parse8XPRadioButton = new JRadioButton();
    private JTextField sourcePathTextField = new JTextField();
    private JButton browseButton = new JButton();
    private JButton parseButton = new JButton();
    private JScrollPane outputScrollPane = new JScrollPane();
    private JTextArea outputTextArea = new JTextArea();
    private String parseMode;
    
    /**
     * Constructs a new parser window
     */
    public ParserWindow() {
        
        // Sets the window bar text
        this.setTitle("TI Parser - BETA 1.2");
        
        /* Initializes the file chooser that will be used to choose which file data will be
         * extracted from
         */
        browseFileChooser.setAcceptAllFileFilterUsed(false);
        
        /* Sets several options for the actual Parser Window
         *     The program exits when the window closes
         *     The window is not resizable
         */
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLocation(new java.awt.Point(50, 50));
        setResizable(false);
        
        // Initializes the radio buttons that will be used to change the parser mode
        parseTXTRadioButton.setSelected(true);
        parseTXTRadioButton.setText("Parse to .8xp");
        parseTXTRadioButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                parseModeChanged(event);
            }
        });
        
        parse8XPRadioButton.setText("Parse to .txt");
        parse8XPRadioButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                parseModeChanged(event);
            }
        });
        
        /* Configures the two radio buttons in a button group so that only one of them can be
         * selected at one time
         */
        parseModeRadioButtonGroup.add(parseTXTRadioButton);
        parseModeRadioButtonGroup.add(parse8XPRadioButton);
        
        // Initializes the "Browse" button which will be used to open the file chooser
        browseButton.setText("Browse...");
        browseButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                browseButtonActionPerformed();
            }
        });
        
        // Initializes the "Parse" button which will start the parser when clicked
        parseButton.setText("Parse");
        parseButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                parseButtonActionPerformed();
            }
        });
        
        /* Initializes the output scroll pane and text area to be used for reporting progress
         * to the user
         * This setup is referred to as the "console"
         */
        outputTextArea.setColumns(20);
        outputTextArea.setRows(5);
        outputTextArea.setEditable(false);
        outputScrollPane.setViewportView(outputTextArea);
        
        /* Builds the layout for the window with all the previously
         * initialized components
         */
        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(outputScrollPane, GroupLayout.DEFAULT_SIZE, 404,
                                (int)Short.MAX_VALUE))
                    .addGroup(GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(parseTXTRadioButton)
                                .addGap(18, 18, 18)
                                .addComponent(parse8XPRadioButton))
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(sourcePathTextField, GroupLayout.PREFERRED_SIZE,
                                        295, GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(browseButton, GroupLayout.DEFAULT_SIZE,
                                        GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
                .addContainerGap())
            .addGroup(layout.createSequentialGroup()
                .addGap(157, 157, 157)
                .addComponent(parseButton, GroupLayout.DEFAULT_SIZE, 130, Short.MAX_VALUE)
                .addGap(157, 157, 157))
        );
        
        layout.setVerticalGroup(
            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(parse8XPRadioButton)
                    .addComponent(parseTXTRadioButton))
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                    .addComponent(sourcePathTextField, GroupLayout.PREFERRED_SIZE, GroupLayout
                               .DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(browseButton))
                .addGap(3, 3, 3)
                .addComponent(parseButton)
                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(outputScrollPane, GroupLayout.DEFAULT_SIZE, 199, Short.MAX_VALUE)
                .addContainerGap())
        );
        pack();
        
        parseMode = "TXT";
        
        System.out.println("Parser window initiate\nParser mode set to \"TXT\"");
    }
    
    /**
     * Gets the text currently in the source path text field
     * @return the text in the source path text field
     */
    public String getFilePath() {
        return sourcePathTextField.getText();
    }
    
    /**
     * Gets the text currently in the output console of the window
     * @return the text in the output console
     */
    public String getConsoleText() {
        return outputTextArea.getText();
    }
    
    /**
     * Sets the console text to the specified String
     * @param text the text that is put in the console
     * @return void
     */
    public void setConsoleText(String text) {
        outputTextArea.setText(text);
    }
    
    /**
     * Appends the specified String to the text currently in the console
     * @param text the text that is added to the console
     * @return void
     */
    public void appendToConsole(String text) {
        outputTextArea.setText(outputTextArea.getText() + text + "\n");
    }
    
    /**
     * Clears the console
     */
    public void clearConsole() {
        outputTextArea.setText("");
    }
        
    /**
     * Gets the current mode of the parser
     * @return the current mode of the parser
     */
    public String getParseMode() {
        return parseMode;
    }
    
    /**
     * This method runs when the parse mode is changed using the parse mode radio buttons
     * @param event the event that triggered the action listener
     * @return void
     */
    private void parseModeChanged(ActionEvent event) {                                  
        
        JRadioButton source = (JRadioButton) event.getSource();
        
        if (source.getText().equals("Parse to .8xp")) {
            parseMode = "TXT";
        }
        
        if (source.getText().equals("Parse to .txt")) {
            parseMode = "8XP";
        }
        
        System.out.println("Parser mode changed to \"" + parseMode + "\"");
    }                                 
    
    /**
     * This method runs when the browse button is clicked
     * @return void
     */
    private void browseButtonActionPerformed() {                                             

        FileFilter[] fileFilterArray = new FileFilter[0];
        FileFilter fileFilter = null;
        
        if (parseMode.equals("TXT")) {
            fileFilterArray = browseFileChooser.getChoosableFileFilters();
            if (fileFilterArray.length != 0) {
                fileFilter = fileFilterArray[0];
            }
            browseFileChooser.removeChoosableFileFilter(fileFilter);
            browseFileChooser.addChoosableFileFilter(new TXTFilter());
        } else if (parseMode.equals("8XP")) {
            fileFilterArray = browseFileChooser.getChoosableFileFilters();
            if (fileFilterArray.length != 0) {
                fileFilter = fileFilterArray[0];
            }
            browseFileChooser.removeChoosableFileFilter(fileFilter);
            browseFileChooser.addChoosableFileFilter(new BXPFilter());
        }
        
        System.out.println("Open File Dialog initiate\nFile filter is set to " + 
                browseFileChooser.getFileFilter());

        int returnValue = browseFileChooser.showOpenDialog(this);
        if (returnValue == JFileChooser.APPROVE_OPTION) {
            File file = browseFileChooser.getSelectedFile();
            sourcePathTextField.setText(file.getAbsolutePath());
        } else {
            System.err.println("File access cancelled by user.");
        }
    }
    
    /**
     * Runs when the parse button is clicked
     * Calls the Static methods of the Parser which then begins actually parsing
     * the input file
     * @return void
     */
    private void parseButtonActionPerformed() {
        
        parseButton.setEnabled(false);
        
        try {
            new Parser().initiate(parseMode);
        } catch(Parser.ParserModeException parserModeException) {
            System.err.println(parserModeException.getMessage());
            appendToConsole("ERROR: " + parserModeException.getMessage());
        } catch(FileNotFoundException fileNotFoundException) {
            System.err.println(fileNotFoundException.getMessage());
            appendToConsole("ERROR: The file does not exist!");
        }
        
        parseButton.setEnabled(true);
    }
        
    /**
     * This internal class is designed to be used by the open file dialog to filter which files
     * can be opened
     */
    private class TXTFilter extends FileFilter {
        
        public boolean accept(File file) {
            return file.isDirectory() || file.getAbsolutePath().endsWith(".txt");
        }
        
        public String getDescription() {
            return "Plain Text (.txt)";
        }
        
        public String toString() {
            return "\"Plain Text\"";
        }
    }
    
    /**
     * This internal class is designed to be used by the open file dialog to filter which files
     * can be opened
     */
    private class BXPFilter extends FileFilter {
        
        public boolean accept(File file) {
            return file.isDirectory() || file.getAbsolutePath().endsWith(".8xp");
        }
        
        public String getDescription() {
            return "TI-84 Program (.8xp)";
        }
        
        public String toString() {
            return "\"TI-84 Program\"";
        }
    }
}
